package com.yilin.tms.order.service.order.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yilin.commons.exception.BusinessException;
import com.yilin.commons.util.*;
import com.yilin.tms.core.application.PageData;
import com.yilin.tms.core.commons.base.BaseEntity;
import com.yilin.tms.core.commons.model.AuthStatus;
import com.yilin.tms.core.commons.annotation.Explain;
import com.yilin.tms.core.commons.utils.OrderUtil;
import com.yilin.tms.core.commons.utils.ParamUtil;
import com.yilin.tms.core.entity.gps.hyb.FenceInfoDTO;
import com.yilin.tms.core.entity.order.clearing.ClearingDetail;
import com.yilin.tms.core.entity.order.clearing.GatherRecord;
import com.yilin.tms.core.entity.order.goods.GoodsOrder;
import com.yilin.tms.core.entity.order.goods.GoodsOrderNoteDetail;
import com.yilin.tms.core.entity.order.goods.ordinary.GoodsNote;
import com.yilin.tms.core.entity.order.goods.ordinary.GoodsOrdinary;
import com.yilin.tms.core.entity.order.party.ReceiptChangeRecord;
import com.yilin.tms.core.entity.order.payment.OrderPaymentCost;
import com.yilin.tms.core.entity.order.rob.RobOrder;
import com.yilin.tms.core.entity.order.transit.TransitOrderNote;
import com.yilin.tms.core.entity.order.transit.TransitOrderNoteDetail;
import com.yilin.tms.core.entity.order.transit.TransitOrder;
import com.yilin.tms.core.entity.order.transit.TransitOrderVehicleRecord;
import com.yilin.tms.core.entity.truck.TransportLicense;
import com.yilin.tms.core.entity.truck.TravelLicense;
import com.yilin.tms.core.entity.truck.TruckVehicle;
import com.yilin.tms.core.entity.user.UserType;
import com.yilin.tms.core.entity.user.account.Account;
import com.yilin.tms.core.entity.user.auth.DrivingLicense;
import com.yilin.tms.core.entity.user.auth.QualificationCert;
import com.yilin.tms.core.entity.user.organize.MemberType;
import com.yilin.tms.core.remote.*;
import com.yilin.tms.order.mapper.clearing.GatherRecordMapper;
import com.yilin.tms.order.mapper.goods.GoodsOrderNoteDetailMapper;
import com.yilin.tms.order.mapper.party.ReceiptChangeRecordMapper;
import com.yilin.tms.order.mapper.rob.RobOrderMapper;
import com.yilin.tms.order.mapper.transit.TransitOrderMapper;
import com.yilin.tms.order.mapper.transit.TransitOrderNoteDetailMapper;
import com.yilin.tms.order.mapper.transit.TransitOrderNoteMapper;
import com.yilin.tms.order.mapper.transit.TransitOrderVehicleRecordMapper;
import com.yilin.tms.order.service.clearing.impl.ClearingService;
import com.yilin.tms.order.service.order.ITransitService;
import com.yilin.tms.order.service.owner.ITransitOwnerService;
import com.yilin.tms.order.service.party.IOrderAutLogService;
import com.yilin.tms.order.service.payment.IOrderPaymentCostService;
import com.yilin.tms.order.service.payment.IOrderSettlementCostService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 运单Service
 *
 * @author zhangjinyuan
 * @date 2022/10/29
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class TransitService extends ServiceImpl<TransitOrderMapper, TransitOrder> implements ITransitService {

    @Resource
    ClearingService clearingService;
    @Resource
    ITransitOwnerService transitOwnerService;
    @Resource
    IOrderAutLogService orderAutLogService;
    @Resource
    IOrderPaymentCostService orderPaymentCostService;
    @Resource
    IOrderSettlementCostService settlementCostService;

    @Resource
    IUserRemote userRemote;
    @Resource
    IMessageRemote messageRemote;
    @Resource
    IDataRemote dataRemote;
    @Resource
    IVehicleRemote vehicleRemote;
    @Resource
    IGpsRemote gpsRemote;

    @Resource
    TransitOrderMapper transitOrderMapper;
    @Resource
    TransitOrderNoteMapper transitOrderNoteMapper;
    @Resource
    TransitOrderNoteDetailMapper transitOrderNoteDetailMapper;
    @Resource
    TransitOrderVehicleRecordMapper transitOrderVehicleRecordMapper;

    @Resource
    RobOrderMapper robOrderMapper;
    @Resource
    GoodsOrderNoteDetailMapper goodsOrderNoteDetailMapper;
    @Resource
    GatherRecordMapper gatherRecordMapper;
    @Resource
    ReceiptChangeRecordMapper receiptChangeRecordMapper;


    /**
     * 保存普通货物  司机自己生成
     */
    @Override
    @Transactional
    public void saveOrdinary(Account logAccount, GoodsOrdinary goodsOrdinary, List<GoodsNote> goodsNoteList, TruckVehicle truckVehicle) {
        AtomicReference<Double> totalPrice = new AtomicReference<>(0d);//总价
        AtomicReference<Double> totalMeasure = new AtomicReference<>(0d);//重量
        goodsNoteList.forEach(goodsNote -> {
            ParamUtil.isNull(goodsNote.getGoodsName(),"存在商品名称为空");
            ParamUtil.isNull(goodsNote.getGoodsWeight(),"存在商品重量为空");
            ParamUtil.isNull(goodsNote.getGoodsPrice(),"存在商品单价为空");
            totalMeasure.updateAndGet(v -> v + goodsNote.getGoodsWeight());
            totalPrice.updateAndGet(v -> new Double(v + MathUtil.multiply(goodsNote.getGoodsWeight(), goodsNote.getGoodsPrice(), 2)));
        });
        TransitOrder transitOrder = new TransitOrder();
        transitOrder.setTransitStatus(TransitOrder.TransitStatus.waitingTransit);
        transitOrder.setTmsOrderCreateState(TransitOrder.TmsOrderCreateState.needless);
        transitOrder.setTransportNo(DateTimeUtil.dateNo("TD"));
        transitOrder.setTitle("普通运输");
        transitOrder.setGoodsOrderType(GoodsOrder.GoodsOrderType.ordinaryOrder);
        transitOrder.setPriceMode(GoodsOrder.PriceMode.wholePrice);
        transitOrder.setSettlementType(GoodsOrder.SettlementType.loadingWav);
        transitOrder.setGoodsRemark(goodsOrdinary.getRemark());
        transitOrder.setGoodsTypeName(goodsNoteList.get(0).getGoodsName());
        transitOrder.setTransportTypeCode("PT0000");
        transitOrder.setMeasureUnit("吨");
        transitOrder.setTransitTruckTypeName("普通运输");
        transitOrder.setShipperEmbarkMeasure(totalMeasure.get());
        transitOrder.setShipperTotalMeasure(totalMeasure.get());
        transitOrder.setFullLoad(true);
        transitOrder.setNeedUploadShipping(true);
        transitOrder.setNeedUploadReceipt(true);
        transitOrder.setSkipConfirmReceipt(true);
        transitOrder.setShipperAccountName(goodsOrdinary.getConsignorName());
        transitOrder.setShipperAccountPhone(goodsOrdinary.getConsignorPhone());
        transitOrder.setShipperAccountPhone(goodsOrdinary.getConsignorPhone());
        //车
        transitOrder.setRobOrderId(truckVehicle.getOrganizeId());
        transitOrder.setRobOrganizeName(truckVehicle.getOrganizeName());
        transitOrder.setRobOrganizeLogo(truckVehicle.getOrganizeLogo());
        transitOrder.setRobAccountId(truckVehicle.getManageUserId());
        transitOrder.setRobAccountName(truckVehicle.getManageUserName());
        transitOrder.setRobAccountPhone(truckVehicle.getManageUserPhone());
        transitOrder.setRobAccountAvatar(truckVehicle.getManageUserAvatar());
        transitOrder.setRobGroupId(logAccount.getSuperiorPlatId());
        transitOrder.setTransitTruckId(truckVehicle.getId());
        transitOrder.setVehicleImageUrl(truckVehicle.getVehicleImageUrl());
        transitOrder.setTransitTruckNo(truckVehicle.getTrackNo());
        transitOrder.setTransitTruckPlateColor(truckVehicle.getCardPlateName());
        transitOrder.setTransitTruckWeight(truckVehicle.getVehicleWeight());
        transitOrder.setTransitTruckLoadingWeight(truckVehicle.getLoadingWeight());
        transitOrder.setTransitTruckTypeName(truckVehicle.getTruckTypeName());
        transitOrder.setTransitTruckTowingType(truckVehicle.getTruckTypeTowingType());
        if (StringUtil.isNotEmpty(truckVehicle.getTractorNo())) {
            TruckVehicle truckVehicleTraile = ParamUtil.isSuccess(vehicleRemote.getTruckByTruckNo(truckVehicle.getTractorNo()));
            transitOrder.setTransitTrailerId(truckVehicleTraile.getTrackNo());
            transitOrder.setTransitTrailerNo(truckVehicleTraile.getTractorNo());
            transitOrder.setTransitTrailerWeight(truckVehicleTraile.getVehicleWeight());
            transitOrder.setTransitTrailerLoadingWeight(truckVehicleTraile.getLoadingWeight());
        }
        transitOrder.setTransitTruckUserId(truckVehicle.getTruckUserId());
        transitOrder.setTransitTruckUserName(truckVehicle.getTruckUserName());
        transitOrder.setTransitTruckUserPhone(truckVehicle.getTruckUserPhone());
        transitOrder.setTransitTruckUserAvatar(truckVehicle.getTruckUserAvatar());
        transitOrder.setDisplayConsignorArea(goodsOrdinary.getConsignorArea());
        transitOrder.setDisplayConsignorAddress(goodsOrdinary.getConsignorAddress());
        transitOrder.setDisplayConsigneeAddress(goodsOrdinary.getConsigneeAddress());
        transitOrder.setDisplayConsigneeArea(goodsOrdinary.getConsigneeArea());
        transitOrder.setGoodsCreateTime(new Date());
        transitOrder.setPricingTransportCost(totalPrice.get());
        transitOrder.setAssignTime(new Date());
        transitOrder.setAssignMeasure(totalMeasure.get());
        transitOrder.setAssignTransportCost(totalPrice.get());
        transitOrder.setLoadingTime(new Date());
        transitOrder.setLoadingMeasure(totalMeasure.get());
        transitOrder.setLoadingTransportCost(totalPrice.get());
        save(transitOrder);
        TransitOrderNote transitOrderNote = new TransitOrderNote();
        transitOrderNote.setTransitOrderId(transitOrder.getId());
        transitOrderNote.setMeasureUnit("吨");
        transitOrderNote.setNoteStatus(TransitOrderNote.NoteStatus.waitDeliver);
        transitOrderNote.setNoteSort(0);
        transitOrderNote.setNoteAssignTime(new Date());
        transitOrderNote.setNoteAssignMeasure(totalMeasure.get());
        transitOrderNote.setNoteAssignTransportCost(totalPrice.get());
        transitOrderNote.setNoteAssignMeasure(totalMeasure.get());
        transitOrderNote.setNoteAssignTransportCost(totalPrice.get());
        transitOrderNoteMapper.insert(transitOrderNote);
        for (int i = 0; i < goodsNoteList.size(); i++) {
            TransitOrderNoteDetail transitOrderNoteDetail = new TransitOrderNoteDetail();
            transitOrderNoteDetail.setGoodsTypeName("普通运输");
            transitOrderNoteDetail.setGoodsName(goodsNoteList.get(0).getGoodsName());
            transitOrderNoteDetail.setGoodsDescribe(goodsNoteList.get(0).getRemark());
            transitOrderNoteDetail.setAssignMeasure(goodsNoteList.get(0).getGoodsWeight());
            Double price = MathUtil.multiply(goodsNoteList.get(0).getGoodsPrice(), goodsNoteList.get(0).getGoodsWeight(), 2);
            transitOrderNoteDetail.setAssignTransportCost(price);
            transitOrderNoteDetail.setLoadingMeasure(goodsNoteList.get(0).getGoodsWeight());
            transitOrderNoteDetail.setLoadingTransportCost(price);
            transitOrderNoteDetail.setLoadingMeasure(goodsNoteList.get(0).getGoodsWeight());
            transitOrderNoteDetail.setLoadingTransportCost(price);
            transitOrderNoteDetail.setDeliverMeasure(goodsNoteList.get(0).getGoodsWeight());
            transitOrderNoteDetail.setDeliverTransportCost(price);
            transitOrderNoteDetailMapper.insert(transitOrderNoteDetail);
        }


    }

    /**
     * 获取运单分页
     */
    @Override
    public PageData<TransitOrder> getTransitOrderPage(Account loginUser, TransitOrder query, Integer start, Integer limit) {
        List<Integer> statuses = new ArrayList<>();
        if (query.getQueryStatuses() != null && query.getQueryStatuses().length > 0) {
            List<TransitOrder.TransitStatus> statusList = Arrays.asList(query.getQueryStatuses());
            statuses = ArrayUtil.fieldAdd(statusList, obj -> obj.index);
        }
        PageData<TransitOrder> pageData = new PageData<>(start, limit);
        pageData.addOrder(OrderItem.desc("create_time"));
        PageData<TransitOrder> page = transitOrderMapper.getTransitOrderPage(pageData, loginUser, query, statuses);
        List<String> idList = ArrayUtil.fieldAdd(page.getList(), BaseEntity::getId);
        //批量获取两个点的预付单
        if (!idList.isEmpty()) {
            List<OrderPaymentCost> deliveryPaymentList = orderPaymentCostService.getOrderPaymentByTransitOrderIds(idList, OrderPaymentCost.PaySite.delivery);
            List<OrderPaymentCost> receiptPaymentList = orderPaymentCostService.getOrderPaymentByTransitOrderIds(idList, OrderPaymentCost.PaySite.receipt);
            List<ReceiptChangeRecord> receiptRecordList = getMutiChangeNoteReceiptRecordList(idList);
            for (TransitOrder transitOrder : page.getList()) {
                OrderPaymentCost deliveryPaymentCost = ArrayUtil.getBy(deliveryPaymentList, obj -> obj.getTransitOrderId().equals(transitOrder.getId()));
                OrderPaymentCost receiptPaymentCost = ArrayUtil.getBy(receiptPaymentList, obj -> obj.getTransitOrderId().equals(transitOrder.getId()));
                List<ReceiptChangeRecord> receiptChangeRecordList = ArrayUtil.whereBy(receiptRecordList, obj -> obj.getTransitOrderId().equals(transitOrder.getId()));
                //获取前台操作标识
                transitOwnerService.getCanOperationMark(loginUser, transitOrder, deliveryPaymentCost, receiptPaymentCost, receiptChangeRecordList);
                //获取运单详情链接
                transitOrder.setTransitOrderDetailUrl(transitOwnerService.getTransitOrderDetailUrl(transitOrder.getId()));
            }
        }
        return page;
    }

    /**
     * 获取运单详情
     */
    @Override
    public TransitOrder getTransitOrderDetail(Account loginUser, String transitOrderId) {
        TransitOrder transitOrder = transitOrderMapper.selectById(transitOrderId);
        if (transitOrder == null) throw new BusinessException("未知的运单");
        transitOrder.setTransitOrderNoteList(getTransitOrderNoteList(transitOrderId, null));
        //前台操作标识
        OrderPaymentCost deliveryPayment = orderPaymentCostService.getOrderPaymentByTransitOrderId(transitOrderId, OrderPaymentCost.PaySite.delivery);
        OrderPaymentCost receiptPayment = orderPaymentCostService.getOrderPaymentByTransitOrderId(transitOrderId, OrderPaymentCost.PaySite.receipt);
        List<ReceiptChangeRecord> receiptRecordList = getChangeNoteReceiptRecordList(transitOrderId);
        transitOwnerService.getCanOperationMark(loginUser, transitOrder, deliveryPayment, receiptPayment, receiptRecordList);
        //获取货源详情链接
        transitOrder.setTransitOrderDetailUrl(transitOwnerService.getTransitOrderDetailUrl(transitOrderId));
        return transitOrder;
    }

    /**
     * 获取司机正在运行中的运单
     * 需要操作的
     */
    @Override
    public List<TransitOrder> getRunTransitOrderListByDriver(String driverUserId) {
        Account account = ParamUtil.isSuccess(userRemote.getAccountById(driverUserId));
        QueryWrapper<TransitOrder> queryWrapper = new QueryWrapper<>();
        List<Integer> queryStatus = new ArrayList<>();
        queryStatus.add(TransitOrder.TransitStatus.waitingLoading.index);
        queryStatus.add(TransitOrder.TransitStatus.waitingDelivery.index);
        queryStatus.add(TransitOrder.TransitStatus.waitingTransit.index);
        queryStatus.add(TransitOrder.TransitStatus.waitingArrive.index);
        queryWrapper.in("transit_status", queryStatus);
        List<Integer> operateStatus = new ArrayList<>();
        operateStatus.add(TransitOrder.OperateStatus.none.ordinal());
        queryWrapper.in("operate_status", operateStatus);
        queryWrapper.eq("transit_truck_user_id", driverUserId);
        List<TransitOrder> transitOrderList = transitOrderMapper.selectList(queryWrapper);
        List<String> idList = ArrayUtil.fieldAdd(transitOrderList, BaseEntity::getId);
        //批量获取两个点的预付单
        if (!idList.isEmpty()) {
            List<OrderPaymentCost> deliveryPaymentList = orderPaymentCostService.getOrderPaymentByTransitOrderIds(idList, OrderPaymentCost.PaySite.delivery);
            List<OrderPaymentCost> receiptPaymentList = orderPaymentCostService.getOrderPaymentByTransitOrderIds(idList, OrderPaymentCost.PaySite.receipt);
            List<ReceiptChangeRecord> receiptRecordList = getMutiChangeNoteReceiptRecordList(idList);
            for (TransitOrder transitOrder : transitOrderList) {
                OrderPaymentCost deliveryPaymentCost = ArrayUtil.getBy(deliveryPaymentList, obj -> obj.getTransitOrderId().equals(transitOrder.getId()));
                OrderPaymentCost receiptPaymentCost = ArrayUtil.getBy(receiptPaymentList, obj -> obj.getTransitOrderId().equals(transitOrder.getId()));
                List<ReceiptChangeRecord> receiptChangeRecordList = ArrayUtil.whereBy(receiptRecordList, obj -> obj.getTransitOrderId().equals(transitOrder.getId()));
                //获取前台操作标识
                transitOwnerService.getCanOperationMark(account, transitOrder, deliveryPaymentCost, receiptPaymentCost, receiptChangeRecordList);
                //获取运单详情链接
                transitOrder.setTransitOrderDetailUrl(transitOwnerService.getTransitOrderDetailUrl(transitOrder.getId()));
            }
        }
        return transitOrderList;
    }

    /**
     * 获取需要汇总的运单
     */
    @Override
    public List<TransitOrder> getGatherTransitOrderList(Account loginUser, String shipperOrganizeId, String robOrganizeId,
                                                        String receiptTimeRange, Boolean matching, Boolean includedTax, String transitTruckNo) {
        String receiptTimeRangeStart = null, receiptTimeRangeEnd = null;
        if (receiptTimeRange != null) {
            String[] range = receiptTimeRange.split("至");
            receiptTimeRangeStart = String.format("%s 00:00:00", range[0]);
            receiptTimeRangeEnd = String.format("%s 23:59:59", range[1]);
        }
        QueryWrapper<GatherRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("gather_status", GatherRecord.GatherStatus.create, GatherRecord.GatherStatus.confirmed);
        List<GatherRecord> recordList = gatherRecordMapper.selectList(queryWrapper);
        List<String> idList = ArrayUtil.fieldAdd(recordList, GatherRecord::getTransitOrderIds);
        List<String> gatherIdList = ArrayUtil.initList(String.join(",", idList).split(","));
        return transitOrderMapper.getGatherTransitOrderList(loginUser, gatherIdList, shipperOrganizeId, robOrganizeId, receiptTimeRangeStart, receiptTimeRangeEnd, matching, includedTax, transitTruckNo);
    }

    /**
     * 获取需要汇总货主下拉列表
     */
    @Override
    public List<Map<String, Object>> getGatherShipperDropList(Account loginUser) {
        return transitOrderMapper.getGatherShipperDropList(loginUser);
    }

    /**
     * 获取需要汇总车主下拉列表
     */
    @Override
    public List<Map<String, Object>> getGatherTruckerDropList(Account loginUser) {
        return transitOrderMapper.getGatherTruckerDropList(loginUser);
    }

    /**
     * 获取需要打印票单材料的运单
     */
    @Override
    public List<TransitOrder> getBillTransitOrderList(Account loginUser, String robOrganizeId, String timeRange) {
        String timeRangeStart, timeRangeEnd;
        if (timeRange == null) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            calendar.add(Calendar.MONTH, -3);
            timeRangeStart = String.format("%s 00:00:00", DateTimeUtil.getDateTimeSpliceStr(calendar.getTime()));
            timeRangeEnd = String.format("%s 23:59:59", DateTimeUtil.getDateTimeSpliceStr(new Date()));
        } else {
            String[] range = timeRange.split("至");
            timeRangeStart = String.format("%s 00:00:00", range[0]);
            timeRangeEnd = String.format("%s 23:59:59", range[1]);
        }
        return transitOrderMapper.getBillTransitOrderList(loginUser, robOrganizeId, timeRangeStart, timeRangeEnd);
    }

    /**
     * 获取运单分页 隐藏敏感信息
     */
    @Override
    public PageData<TransitOrder> getPublicTransitOrderPage(TransitOrder query, Integer start, Integer limit) {
        PageData<TransitOrder> pageData = transitOrderMapper.getTransitOrderPage(new PageData<>(start, limit), new Account(), query, null);
        for (TransitOrder transitOrder : pageData.getList()) {
            //隐藏敏感信息
            transitOwnerService.transitOrderPrivateData(transitOrder);
            //获取运单详情链接
            transitOrder.setTransitOrderDetailUrl(transitOwnerService.getTransitOrderDetailUrl(transitOrder.getId()));
        }
        return pageData;
    }

    /**
     * 获取节点列表
     */
    @Override
    public List<TransitOrderNote> getTransitOrderNoteList(String transitOrderId, TransitOrderNote.NoteStatus noteStatus) {
        return getTransitOrderNoteList(transitOrderId, noteStatus, true);
    }

    @Override
    public List<TransitOrderNote> getTransitOrderNoteList(String transitOrderId, TransitOrderNote.NoteStatus noteStatus, boolean contains) {
        QueryWrapper<TransitOrderNote> wrapper = new QueryWrapper<>();
        wrapper.eq("transit_order_id", transitOrderId);
        if (noteStatus != null) wrapper.eq("note_status", noteStatus.index);
        wrapper.orderByAsc("note_sort");
        List<TransitOrderNote> transitOrderNoteList = transitOrderNoteMapper.selectList(wrapper);
        if (contains) {
            transitOrderNoteList.forEach(transitOrderNote -> {
                List<TransitOrderNoteDetail> transitOrderNoteDetailList = getTransitOrderNoteDetailList(transitOrderNote.getId());
                transitOrderNoteDetailList.forEach(transitOrderNoteDetail -> {
                    GoodsOrderNoteDetail goodsOrderNoteDetail = goodsOrderNoteDetailMapper.selectById(transitOrderNoteDetail.getGoodsOrderNoteDetailId());
                    transitOrderNoteDetail.setGoodsOrderNoteDetail(goodsOrderNoteDetail);
                });
                transitOrderNote.setTransitOrderNoteDetailList(transitOrderNoteDetailList);
            });
        }
        return transitOrderNoteList;
    }

    /**
     * 获取节点信息
     */
    @Override
    public TransitOrderNote getTransitOrderNoteById(String transitOrderNoteId) {
        return transitOrderNoteMapper.selectById(transitOrderNoteId);
    }

    /**
     * 获取节点货物列表
     */
    @Override
    public List<TransitOrderNoteDetail> getTransitOrderNoteDetailList(String transitOrderNoteId) {
        QueryWrapper<TransitOrderNoteDetail> detailQueryWrapper = new QueryWrapper<>();
        detailQueryWrapper.eq("transit_order_note_id", transitOrderNoteId);
        List<TransitOrderNoteDetail> transitOrderNoteDetailList = transitOrderNoteDetailMapper.selectList(detailQueryWrapper);
        transitOrderNoteDetailList.forEach(transitOrderNoteDetail -> {
            GoodsOrderNoteDetail goodsOrderNoteDetail = goodsOrderNoteDetailMapper.selectById(transitOrderNoteDetail.getGoodsOrderNoteDetailId());
            transitOrderNoteDetail.setGoodsOrderNoteDetail(goodsOrderNoteDetail);
        });
        return transitOrderNoteDetailList;
    }

    /**
     * 获取运单货物列表
     */
    @Override
    public List<TransitOrderNoteDetail> getAllTransitOrderDetailList(String transitOrderId) {
        QueryWrapper<TransitOrderNoteDetail> detailQueryWrapper = new QueryWrapper<>();
        detailQueryWrapper.eq("transit_order_id", transitOrderId);
        List<TransitOrderNoteDetail> transitOrderNoteDetailList = transitOrderNoteDetailMapper.selectList(detailQueryWrapper);
        for (TransitOrderNoteDetail transitOrderNoteDetail : transitOrderNoteDetailList) {
            GoodsOrderNoteDetail goodsOrderNoteDetail = goodsOrderNoteDetailMapper.selectById(transitOrderNoteDetail.getGoodsOrderNoteDetailId());
            transitOrderNoteDetail.setGoodsOrderNoteDetail(goodsOrderNoteDetail);
        }
        return transitOrderNoteDetailList;
    }

    /**
     * 获取节点数量
     */
    @Override
    public int getTransitOrderNoteCount(String transitOrderId, TransitOrderNote.NoteStatus noteStatus) {
        QueryWrapper<TransitOrderNote> wrapper = new QueryWrapper<>();
        wrapper.eq("transit_order_id", transitOrderId);
        if (noteStatus != null) wrapper.eq("note_status", noteStatus.index);
        Long aLong = transitOrderNoteMapper.selectCount(wrapper);
        return aLong.intValue();
    }

    /**
     * 地图包：待装货
     */
    @Override
    public Map<String, Object> getMapNoteDataListByLoading(String transitOrderId, String truckLngLat) {
        Map<String, Object> sortGpsMapNoteData = new HashMap<>();
        //### 所有等待装货的数据,用司机点位对发货坐标数据进行排序
        List<TransitOrderNote> loadingTransitOrderNoteList = getTransitOrderNoteList(transitOrderId, TransitOrderNote.NoteStatus.waitLoading);
        loadingTransitOrderNoteList = OrderUtil.sortORLatLngList(loadingTransitOrderNoteList, truckLngLat);
        //### 获取所有节点数据,用等待装货最后一个收货坐标进行排序
        List<TransitOrderNote> allTransitOrderNoteList = getTransitOrderNoteList(transitOrderId, null);
        allTransitOrderNoteList = OrderUtil.sortEELatLngList(allTransitOrderNoteList, ArrayUtil.last(loadingTransitOrderNoteList).getConsigneeCoordinate());
        /// 返回前台用于显示Marker的点位信息
        List<Map<String, Object>> markerList = new ArrayList<>();
        allTransitOrderNoteList.forEach(transitOrderNote -> markerList.add(MapUtil.generate(map -> {
            map.put("consignorMarkerId", transitOrderNote.getConsignorAdCode());
            map.put("consignorMarkerCoordinate", transitOrderNote.getConsignorCoordinate());
            map.put("consignorMarkerTitle", transitOrderNote.getConsignorName());
            map.put("consigneeMarkerId", transitOrderNote.getConsigneeAdCode());
            map.put("consigneeMarkerCoordinate", transitOrderNote.getConsigneeCoordinate());
            map.put("consigneeMarkerTitle", transitOrderNote.getConsigneeName());
        })));
        sortGpsMapNoteData.put("markerList", markerList);
        //### 获取最近点位
        final TransitOrderNote lastTransitOrderNote = ArrayUtil.first(loadingTransitOrderNoteList);
        sortGpsMapNoteData.put("nextNoteInfo", MapUtil.generate(map -> {
            map.put("coordinate", lastTransitOrderNote.getConsignorCoordinate());
            map.put("contactName", lastTransitOrderNote.getConsignorName());
            map.put("contactPhone", lastTransitOrderNote.getConsignorPhone());
            map.put("contactAddress", lastTransitOrderNote.getConsignorAddress());
        }));
        //### 线路规划关键点 点位信息
        List<String> navPlanLngLats = new ArrayList<>();
        loadingTransitOrderNoteList.forEach(transitOrderNote -> navPlanLngLats.add(transitOrderNote.getConsignorCoordinate()));
        allTransitOrderNoteList.forEach(transitOrderNote -> navPlanLngLats.add(transitOrderNote.getConsigneeCoordinate()));
        sortGpsMapNoteData.put("navPlanLngLats", navPlanLngLats);
        return sortGpsMapNoteData;
    }

    /**
     * 地图包：待收货
     */
    @Override
    public Map<String, Object> getMapNoteDataListByReceipt(@Explain("运单ID") String transitOrderId) {
        Map<String, Object> sortGpsMapNoteData = new HashMap<>();
        //### 所有等待装货的数据,用司机点位对收货坐标数据进行排序
        List<TransitOrderNote> receiptTransitOrderNoteList = getTransitOrderNoteList(transitOrderId, TransitOrderNote.NoteStatus.waitReceipt);
        receiptTransitOrderNoteList.sort(Comparator.comparingInt(TransitOrderNote::getNoteSort));
        //### 获取所有节点数据,用等待装货最后一个收货坐标进行排序
        List<TransitOrderNote> allTransitOrderNoteList = getTransitOrderNoteList(transitOrderId, null);
        /// 返回前台用于显示Marker的点位信息
        List<Map<String, Object>> markerList = new ArrayList<>();
        allTransitOrderNoteList.forEach(transitOrderNote -> markerList.add(MapUtil.generate(map -> {
            map.put("consigneeMarkerId", transitOrderNote.getConsigneeAdCode());
            map.put("consigneeMarkerCoordinate", transitOrderNote.getConsigneeCoordinate());
            map.put("consigneeMarkerTitle", transitOrderNote.getConsigneeName());
            map.put("consignorMarkerId", transitOrderNote.getConsignorAdCode());
            map.put("consignorMarkerCoordinate", transitOrderNote.getConsignorCoordinate());
            map.put("consignorMarkerTitle", transitOrderNote.getConsignorName());
        })));
        sortGpsMapNoteData.put("markerList", markerList);
        //### 获取最近点位
        final TransitOrderNote lastTransitOrderNote = ArrayUtil.first(receiptTransitOrderNoteList);
        sortGpsMapNoteData.put("nextNoteInfo", MapUtil.generate(map -> {
            map.put("coordinate", lastTransitOrderNote.getConsigneeCoordinate());
            map.put("contactName", lastTransitOrderNote.getConsigneeName());
            map.put("contactPhone", lastTransitOrderNote.getConsigneePhone());
            map.put("contactAddress", lastTransitOrderNote.getConsigneeAddress());
        }));
        /// 返回前台用于线路规划的点位信息
        sortGpsMapNoteData.put("navPlanLngLats", ArrayUtil.fieldAdd(receiptTransitOrderNoteList, TransitOrderNote::getConsigneeCoordinate));
        return sortGpsMapNoteData;
    }


    /**
     * 确认装货
     * 装货进程中，车主只要触发围栏，就可以更新围栏下的装货信息，无论是否已经装货
     */
    @Override
    public boolean confirmLoading(Account loginUser, TransitOrder localTransitOrder, List<TransitOrderNote> transitOrderNoteList) {
        //计算装车基础运输费并更新运单信息
        for (TransitOrderNote transitOrderNote : transitOrderNoteList) {
            TransitOrderNote localTransitOrderNote = transitOrderNoteMapper.selectById(transitOrderNote.getId());
            double noteLoadingMeasure = 0D, noteLoadingTransportCost = 0D;
            for (TransitOrderNoteDetail transitOrderNoteDetail : transitOrderNote.getTransitOrderNoteDetailList()) {
                TransitOrderNoteDetail localTransitOrderNoteDetail = transitOrderNoteDetailMapper.selectById(transitOrderNoteDetail.getId());
                localTransitOrderNoteDetail.setLoadingMeasure(MathUtil.round(transitOrderNoteDetail.getLoadingMeasure(), 3));
                Double unitPrice = localTransitOrderNoteDetail.getTransitUnitPrice();
                Double loadingTransportCost = MathUtil.multiply(localTransitOrderNoteDetail.getLoadingMeasure(), unitPrice, 2);
                localTransitOrderNoteDetail.setLoadingTransportCost(loadingTransportCost);
                localTransitOrderNoteDetail.setUpdateUserId(loginUser.getId());
                localTransitOrderNoteDetail.setUpdateTime(new Date());
                transitOrderNoteDetailMapper.updateById(localTransitOrderNoteDetail);
                noteLoadingMeasure = MathUtil.add(noteLoadingMeasure, localTransitOrderNoteDetail.getLoadingMeasure());
                noteLoadingTransportCost = MathUtil.add(noteLoadingTransportCost, loadingTransportCost);
            }
            localTransitOrderNote.setNoteLoadingImg(transitOrderNote.getNoteLoadingImg());
            localTransitOrderNote.setNoteLoadingMeasure(noteLoadingMeasure);
            localTransitOrderNote.setNoteLoadingTransportCost(noteLoadingTransportCost);
            localTransitOrderNote.setNoteLoadingTime(new Date());
            localTransitOrderNote.setNoteStatus(TransitOrderNote.NoteStatus.waitDeliver);
            transitOrderNoteMapper.updateById(localTransitOrderNote);
        }
        //获取全部节点，检查是否完成
        QueryWrapper<TransitOrderNote> noteQueryWrapper = new QueryWrapper<>();
        noteQueryWrapper.eq("transit_order_id", localTransitOrder.getId());
        noteQueryWrapper.eq("note_status", TransitOrderNote.NoteStatus.waitLoading.index);
        if (transitOrderNoteMapper.selectCount(noteQueryWrapper) > 0) return false;
        //所有节点已装货完成，计算装总量，完成装货流程
        noteQueryWrapper = new QueryWrapper<>();
        noteQueryWrapper.eq("transit_order_id", localTransitOrder.getId());
        List<TransitOrderNote> localOrderNoteList = transitOrderNoteMapper.selectList(noteQueryWrapper);
        localTransitOrder.setLoadingMeasure(ArrayUtil.numListAdd(localOrderNoteList, TransitOrderNote::getNoteLoadingMeasure));
        localTransitOrder.setLoadingTransportCost(ArrayUtil.numListAdd(localOrderNoteList, TransitOrderNote::getNoteLoadingTransportCost));
        localTransitOrder.setLoadingTime(new Date());
        localTransitOrder.setTransitStatus(TransitOrder.TransitStatus.waitingDelivery);
        localTransitOrder.setUpdateTime(new Date());
        localTransitOrder.setUpdateUserId(loginUser.getId());
        saveOrUpdate(localTransitOrder);
        //保存操作记录
        String loggerText = String.format("运单已装货完成，运单号：%s", localTransitOrder.getTransportNo());
        orderAutLogService.saveTransitAutLog(localTransitOrder.getId(), loginUser, "【装货完成】", loggerText);
        //货主自动发货
        boolean autoDeliver = supportAutoDeliver(loginUser, localTransitOrder);
        //发送通知
        String msg = String.format("尊敬的货主用户您好，您的运单：%s，司机已完成装货，请仔细核对司机装货量后完成发货", localTransitOrder.getTransportNo());
        if (autoDeliver)
            msg = String.format("尊敬的货主用户您好，您的运单：%s，司机已完成装货，系统已为您自动发货，请仔细核对司机装货量", localTransitOrder.getTransportNo());
        Account shipperAccount = ParamUtil.isSuccess(userRemote.getAccountById(localTransitOrder.getShipperAccountId()));
        messageRemote.sendOrderNotify(shipperAccount.getId(), msg, transitOwnerService.getTransitOrderDetailUrl(localTransitOrder.getId()));
        return true;
    }

    /**
     * 确认发货+签订合同
     * 如果支付位置在这里 这里需要判断是否支付
     */
    @Override
    public void confirmDelivery(Account loginUser, TransitOrder localTransitOrder, boolean autoConfirmDelivery) {
        //计算发货基础运输费并更新运单信息
        double totalDeliverMeasure = 0.00, totalDeliverTransportCost = 0.00;
        for (TransitOrderNote transitOrderNote : localTransitOrder.getTransitOrderNoteList()) {
            double noteDeliverMeasure = 0.00, noteDeliverTransportCost = 0.00;
            TransitOrderNote localTransitOrderNote = transitOrderNoteMapper.selectById(transitOrderNote.getId());
            for (TransitOrderNoteDetail transitOrderNoteDetail : transitOrderNote.getTransitOrderNoteDetailList()) {
                TransitOrderNoteDetail localTransitOrderNoteDetail = transitOrderNoteDetailMapper.selectById(transitOrderNoteDetail.getId());
                localTransitOrderNoteDetail.setDeliverMeasure(MathUtil.round(transitOrderNoteDetail.getDeliverMeasure(), 3));
                Double deliverUnitPrice = localTransitOrderNoteDetail.getTransitUnitPrice();
                Double detailDeliverTransportCost = MathUtil.multiply(localTransitOrderNoteDetail.getDeliverMeasure(), deliverUnitPrice, 2);
                localTransitOrderNoteDetail.setDeliverTransportCost(detailDeliverTransportCost);
                localTransitOrderNoteDetail.setUpdateUserId(loginUser.getId());
                localTransitOrderNoteDetail.setUpdateTime(new Date());
                transitOrderNoteDetailMapper.updateById(localTransitOrderNoteDetail);
                noteDeliverMeasure = MathUtil.add(noteDeliverMeasure, localTransitOrderNoteDetail.getDeliverMeasure());
                noteDeliverTransportCost = MathUtil.add(noteDeliverTransportCost, detailDeliverTransportCost);
            }
            localTransitOrderNote.setNoteDeliverMeasure(noteDeliverMeasure);
            localTransitOrderNote.setNoteDeliverTransportCost(noteDeliverTransportCost);
            localTransitOrderNote.setNoteDeliverTime(new Date());
            localTransitOrderNote.setNoteStatus(TransitOrderNote.NoteStatus.waitReceipt);
            transitOrderNoteMapper.updateById(localTransitOrderNote);
            totalDeliverMeasure = MathUtil.add(totalDeliverMeasure, noteDeliverMeasure);
            totalDeliverTransportCost = MathUtil.add(totalDeliverTransportCost, noteDeliverTransportCost);
        }
        localTransitOrder.setDeliverMeasure(totalDeliverMeasure);
        localTransitOrder.setDeliverTransportCost(totalDeliverTransportCost);
        localTransitOrder.setDeliverTime(new Date());
        localTransitOrder.setTransitStatus(TransitOrder.TransitStatus.waitingTransit);
        //生成运单发货预支付单
        RobOrder localRobOrder = robOrderMapper.selectById(localTransitOrder.getRobOrderId());
        OrderPaymentCost paymentCost = orderPaymentCostService.generateDeliveryOrderPayment(localTransitOrder, localRobOrder);
        localTransitOrder.setInsuredCost(paymentCost.getSplitInsuranceCost());
        saveOrUpdate(localTransitOrder);
        //签订合同
        ParamUtil.isSuccess(dataRemote.signContract(localTransitOrder.getId(), localTransitOrder.getShipperAccountId()));
        //保存操作记录
        String loggerText = String.format("运单已成功发货，运单号：%s", localTransitOrder.getTransportNo());
        orderAutLogService.saveTransitAutLog(localTransitOrder.getId(), loginUser, (autoConfirmDelivery ? "【自动发货成功】" : "【发货成功】"), loggerText);
        //推送
        if (!autoConfirmDelivery) {
            String message = String.format("尊敬的司机用户您好，您的运单%s，货主已经完成发货，请仔细核对实际发货量并确认运输", localTransitOrder.getTransportNo());
            messageRemote.sendOrderNotify(localTransitOrder.getTransitTruckUserId(), message, transitOwnerService.getTransitOrderDetailUrl(localTransitOrder.getId()));
        }
    }

    /**
     * 批量发货
     */
    @Override
    public int multiConfirmDelivery(Account loginUser, String[] transitOrderIds) {
        int success = 0;
        for (String transitOrderId : transitOrderIds) {
            TransitOrder localTransitOrder = getById(transitOrderId);
            if (localTransitOrder == null || localTransitOrder.getTransitStatus() != TransitOrder.TransitStatus.waitingDelivery)
                continue;
            QueryWrapper<TransitOrderNote> queryWrapper = new QueryWrapper<TransitOrderNote>().eq("transit_order_id", transitOrderId);
            List<TransitOrderNote> noteList = transitOrderNoteMapper.selectList(queryWrapper);
            for (TransitOrderNote transitOrderNote : noteList) {
                QueryWrapper<TransitOrderNoteDetail> detailWrapper = new QueryWrapper<TransitOrderNoteDetail>().eq("transit_order_note_id", transitOrderNote.getId());
                List<TransitOrderNoteDetail> detailList = transitOrderNoteDetailMapper.selectList(detailWrapper);
                for (TransitOrderNoteDetail transitOrderNoteDetail : detailList) {
                    transitOrderNoteDetail.setDeliverMeasure(transitOrderNoteDetail.getLoadingMeasure());
                    transitOrderNoteDetail.setDeliverTransportCost(transitOrderNoteDetail.getLoadingTransportCost());
                }
            }
            // > SET
            localTransitOrder.setTransitOrderNoteList(noteList);
            localTransitOrder.setDeliverMeasure(localTransitOrder.getLoadingMeasure());
            localTransitOrder.setDeliverTransportCost(localTransitOrder.getLoadingTransportCost());
            confirmDelivery(loginUser, localTransitOrder, false);
            success++;
        }
        return success;
    }

    /**
     * 车主
     * 确认运输+签订合同
     */
    @Override
    public String confirmTransit(Account loginUser, TransitOrder localOrder) {
        localOrder.setTransitStatus(TransitOrder.TransitStatus.waitingArrive);
        localOrder.setUpdateUserId(loginUser.getId());
        localOrder.setUpdateTime(new Date());
        localOrder.setStartTransitTime(new Date());
        //规划排序 获取节点信息
        String[] noteIds = localOrder.getSortConsigneeNoteIds().split(",");
        MemberType memberType = ParamUtil.isSuccess(userRemote.getMyMemberTypeByOrganizeId(loginUser.getOrganizeId()));
        List<FenceInfoDTO> fenceInfoList = new ArrayList<>();
        for (int index = 0; index < noteIds.length; index++) {
            TransitOrderNote transitOrderNote = transitOrderNoteMapper.selectById(noteIds[index]);
            transitOrderNote.setNoteSort(index);
            transitOrderNoteMapper.updateById(transitOrderNote);
            fenceInfoList.add(FenceInfoDTO.genReceiptByTransitOrderNote(transitOrderNote, memberType.getElectronicFenceRange()));
        }
        //生成轨迹ID
//        String traceId = ParamUtil.isSuccess(gpsRemote.createTraceId(localOrder.getPlatId(), localOrder.getGeoServiceId(), localOrder.getGeoTerminalId(), localOrder.getTransportNo()));
//        if (traceId == null) throw new BusinessException("生成轨迹ID失败，请稍后重新发起请求");
//        localOrder.setGeoTrackTraceId(traceId);

        //确认合同
        ParamUtil.isSuccess(dataRemote.signContract(localOrder.getId(), loginUser.getId()));
        TruckVehicle truckVehicle = ParamUtil.isSuccess(vehicleRemote.getVehicleById(localOrder.getTransitTruckId()));
        //若挂车存在，将挂车设为忙碌中
        if (localOrder.getTransitTrailerId() != null) {
            vehicleRemote.updateVehicleStatus(localOrder.getTransitTrailerId(), TruckVehicle.TruckStatus.using);
        }
        //生成保单
        //generateInsuranceData(loginUser, localTransitOrder);
        //保存车辆运输记录
        generateVehicleRecord(localOrder, localOrder.getPlanningConsignorCoordinate(), localOrder.getPlanningConsignorAddress(), localOrder.getPlanningConsignorAdCode());

        //TODO:开始ETC运单
        //更新运单
        updateById(localOrder);
        //保存操作记录
        orderAutLogService.saveTransitAutLog(localOrder.getId(), loginUser, "【确认运输】",
                String.format("运单已确认运输,当前正在运输,运单号:%s", localOrder.getTransportNo()));
        //推送通知
        Account shipperAccount = ParamUtil.isSuccess(userRemote.getAccountById(localOrder.getShipperAccountId()));
        String message = String.format("尊敬的货主用户您好，您的运单：%s，司机方已经开始运输，正在赶往收货点，请耐心等待送达", localOrder.getTransportNo());
        messageRemote.sendOrderNotify(shipperAccount.getId(), message, transitOwnerService.getTransitOrderDetailUrl(localOrder.getId()));
        return null;
    }

    /**
     * 确认送达+生成电子回单
     */
    @Override
    public Boolean confirmArrive(Account loginUser, TransitOrder localOrder, List<TransitOrderNote> transitOrderNoteList) {
        //计算装车基础运输费并更新运单信息
        for (TransitOrderNote transitOrderNote : transitOrderNoteList) {
            TransitOrderNote localTransitOrderNote = transitOrderNoteMapper.selectById(transitOrderNote.getId());
            double noteReceiptMeasure = 0D, noteReceiptTransportCost = 0D, noteDiffIndemnityCost = 0D;
            List<String> noteDiffIndemnityDetailList = new ArrayList<>();
            for (TransitOrderNoteDetail transitOrderNoteDetail : transitOrderNote.getTransitOrderNoteDetailList()) {
                TransitOrderNoteDetail localTransitOrderNoteDetail = transitOrderNoteDetailMapper.selectById(transitOrderNoteDetail.getId());
                localTransitOrderNoteDetail.setReceiptMeasure(MathUtil.round(transitOrderNoteDetail.getReceiptMeasure(), 3));
                Double unitPrice = localTransitOrderNoteDetail.getTransitUnitPrice();
                Double receiptTransportCost = MathUtil.multiply(localTransitOrderNoteDetail.getReceiptMeasure(), unitPrice, 2);
                localTransitOrderNoteDetail.setReceiptTransportCost(receiptTransportCost);
                //计算磅差+赔付金额 赔付去尾
                double diffIndemnityMeasure = MathUtil.subtract(localTransitOrderNoteDetail.getDeliverMeasure(), localTransitOrderNoteDetail.getReceiptMeasure());
                localTransitOrderNoteDetail.setDiffIndemnityMeasure(diffIndemnityMeasure);
                double diffIndemnityCost = MathUtil.multiply(diffIndemnityMeasure, localTransitOrderNoteDetail.getCargoUnitPrice(), 2);
                localTransitOrderNoteDetail.setDiffIndemnityCost(diffIndemnityCost);
                localTransitOrderNoteDetail.setUpdateUserId(loginUser.getId());
                localTransitOrderNoteDetail.setUpdateTime(new Date());
                transitOrderNoteDetailMapper.updateById(localTransitOrderNoteDetail);
                noteReceiptMeasure = MathUtil.add(noteReceiptMeasure, localTransitOrderNoteDetail.getReceiptMeasure());
                noteReceiptTransportCost = MathUtil.add(noteReceiptTransportCost, receiptTransportCost);
                noteDiffIndemnityCost = MathUtil.add(noteDiffIndemnityCost, diffIndemnityCost);
                noteDiffIndemnityDetailList.add(String.format("货物[%s]磅差[%s%s]赔付[%s元]", localTransitOrderNoteDetail.getGoodsName(), diffIndemnityMeasure,
                        localTransitOrderNoteDetail.getMeasureUnit(), diffIndemnityMeasure));
            }
            localTransitOrderNote.setNoteDiffIndemnity(noteDiffIndemnityCost);
            if (noteDiffIndemnityCost > 0) {
                localTransitOrderNote.setNoteDiffIndemnityDetail(localTransitOrderNote.getConsignorName() + "->" + localTransitOrderNote.getConsignorName() +
                        ":" + String.join(",", noteDiffIndemnityDetailList));
            }
            localTransitOrderNote.setNoteReceiptImg(transitOrderNote.getNoteReceiptImg());
            localTransitOrderNote.setNoteReceiptMeasure(noteReceiptMeasure);
            localTransitOrderNote.setNoteReceiptTransportCost(noteReceiptTransportCost);
            localTransitOrderNote.setNoteReceiptTime(new Date());
            localTransitOrderNote.setNoteStatus(TransitOrderNote.NoteStatus.transitEnd);
            transitOrderNoteMapper.updateById(localTransitOrderNote);
            //生成电子回单
            ParamUtil.isSuccess(dataRemote.saveElcReceiptOrder(localTransitOrderNote));
        }
        //获取全部节点，检查是否完成
        QueryWrapper<TransitOrderNote> noteQueryWrapper = new QueryWrapper<>();
        noteQueryWrapper.eq("note_status", TransitOrderNote.NoteStatus.waitReceipt.index);
        noteQueryWrapper.eq("transit_order_id", localOrder.getId());
        if (transitOrderNoteMapper.selectCount(noteQueryWrapper) > 0) return false;
        noteQueryWrapper = new QueryWrapper<>();
        noteQueryWrapper.eq("transit_order_id", localOrder.getId());
        List<TransitOrderNote> localOrderNoteList = transitOrderNoteMapper.selectList(noteQueryWrapper);
        //开始合并计算
        double receiptMeasure = 0, receiptTransportCost = 0, diffIndemnityCost = 0;
        List<String> diffIndemnityDetailList = new ArrayList<>();
        for (TransitOrderNote transitOrderNote : localOrderNoteList) {
            receiptMeasure = MathUtil.add(receiptMeasure, transitOrderNote.getNoteReceiptMeasure());
            receiptTransportCost = MathUtil.add(receiptTransportCost, transitOrderNote.getNoteReceiptTransportCost());
            diffIndemnityCost = MathUtil.add(diffIndemnityCost, transitOrderNote.getNoteDiffIndemnity());
            diffIndemnityDetailList.add(transitOrderNote.getNoteDiffIndemnityDetail());
        }
        localOrder.setReceiptMeasure(receiptMeasure);
        localOrder.setReceiptTransportCost(receiptTransportCost);
        localOrder.setDiffIndemnityCost(diffIndemnityCost);
        localOrder.setDiffIndemnityDetail(String.join(";", diffIndemnityDetailList));
        //时间即状态
        localOrder.setReceiptTime(new Date());
        localOrder.setTransitStatus(TransitOrder.TransitStatus.waitingReceipt);
        //结束车辆运输记录
        finishVehicleRecord(localOrder, localOrder.getPlanningConsigneeAddress(), localOrder.getPlanningConsigneeAddress(), localOrder.getPlanningConsigneeAdCode());
        //更新车辆状态
        TruckVehicle truckVehicle = ParamUtil.isSuccess(vehicleRemote.getVehicleById(localOrder.getTransitTruckId()));
        ParamUtil.isSuccess(vehicleRemote.updateVehicleStatus(localOrder.getTransitTruckId(), TruckVehicle.TruckStatus.unused));
        //若挂车存在，将挂车设为空闲中
        if (localOrder.getTransitTrailerId() != null) {
            vehicleRemote.updateVehicleStatus(localOrder.getTransitTrailerId(), TruckVehicle.TruckStatus.unused);
        }
        //生成签收预支付单
        orderPaymentCostService.generateReceiptOrderPayment(localOrder);

        //判断是否同平台好运宝车辆，清除围栏信息
//        if (truckVehicle.getPlatId().equals(localOrder.getPlatId()) &&truckVehicle.getTruckGpsType() == VehicleGps.TruckGpsType.hyb && truckVehicle.getGpsDeviceId() != null) {
//            EquipmentInfo equipmentInfo = ParamUtil.isSuccess(gpsRemote.getTrackDeviceInfo(truckVehicle.getPlatId(), truckVehicle.getGpsDeviceId()));
//            if (equipmentInfo != null && equipmentInfo.getStatus() != 3) ParamUtil.isSuccess(gpsRemote.deleteStoreDevicePolygon(truckVehicle.getPlatId(),localOrder.getTransportNo()));
//        }

        //TODO:ETC运单结束更新
        localOrder.setUpdateTime(new Date());
        localOrder.setUpdateUserId(loginUser.getId());
        saveOrUpdate(localOrder);
        //保存操作记录
        orderAutLogService.saveTransitAutLog(localOrder.getId(), loginUser, "【确认送达】", String.format("运单已确认送达,运单号:%s", localOrder.getTransportNo()));
        //推送通知
        Account shipperAccount = userRemote.getAccountById(localOrder.getShipperAccountId()).getData();
        //获取自动完成确认收货
        boolean autoReceipt = autoReceipt(loginUser, localOrder);
        String format = String.format("尊敬的货主用户您好，您的运单：%s，司机方已确认送达，系统已生成电子回单，请仔细核对货物信息并及时完成确认收货", localOrder.getTransportNo());
        if (autoReceipt)
            format = String.format("尊敬的货主用户您好，您的运单：%s，司机方已确认送达，系统已生成电子回单并为您自动确认收货，请仔细核对货物信息", localOrder.getTransportNo());
        messageRemote.sendOrderNotify(shipperAccount.getId(), format, transitOwnerService.getTransitOrderDetailUrl(localOrder.getId()));
        return true;
    }

    /**
     * 确认回执
     */
    @Override
    public void confirmReceipt(Account loginUser, TransitOrder transitOrder, boolean autoConfirmReceipt) {
        //计算等待服务费
        MemberType memberType = ParamUtil.isSuccess(userRemote.getMyMemberTypeByOrganizeId(transitOrder.getShipperOrganizeId()));
        int loadingWaitSec = DateTimeUtil.secondBetween(transitOrder.getLoadingTime(), transitOrder.getDeliverTime()) / 60;
        if (loadingWaitSec > memberType.getFreeLoadingWaitingMinute()) {
            double loadingWaitingCost = MathUtil.multiply(MathUtil.subtract(loadingWaitSec * 1.0, memberType.getFreeLoadingWaitingMinute()), memberType.getWaitingUnitCost(), 2);
            String format = String.format("车主装货等待时间：%s分钟，收取等待费：%s元", loadingWaitSec, loadingWaitingCost);
            transitOrder.setAdditionalCost(MathUtil.add(transitOrder.getAdditionalCost(), loadingWaitingCost));
            transitOrder.setAdditionalDetails(transitOrder.getAdditionalDetails() + "；" + format);
        }
        transitOrder.setConfirmTime(new Date());
        int receiptWaitSec = DateTimeUtil.secondBetween(transitOrder.getReceiptTime(), transitOrder.getConfirmTime()) / 60;
        if (receiptWaitSec > memberType.getFreeReceiptWaitingMinute()) {
            double receiptWaitingCost = MathUtil.multiply(MathUtil.subtract(receiptWaitSec * 1.0, memberType.getFreeReceiptWaitingMinute()), memberType.getWaitingUnitCost(), 2);
            String format = String.format("车主卸货等待时间：%s分钟，收取等待费：%s元", receiptWaitSec, receiptWaitingCost);
            transitOrder.setAdditionalCost(MathUtil.add(transitOrder.getAdditionalCost(), receiptWaitingCost));
            transitOrder.setAdditionalDetails(transitOrder.getAdditionalDetails() + "；" + format);
        }
        ClearingDetail clearingDetail = clearingService.createClearingDetail(transitOrder);
        transitOrder.setTransitStatus(TransitOrder.TransitStatus.waitingSettlement);
        transitOrder.setClearingDetailId(clearingDetail.getId());
        transitOrder.setUpdateUserId(loginUser.getId());
        transitOrder.setUpdateTime(new Date());
        updateById(transitOrder);
        //保存操作记录
        orderAutLogService.saveTransitAutLog(transitOrder.getId(), loginUser, "【确认签收】", String.format("运单已确认签收,运单号:%s", transitOrder.getTransportNo()));
        //推送通知
        Account robAccount = ParamUtil.isSuccess(userRemote.getAccountById(transitOrder.getRobAccountId()));
        //自动清算
        boolean clearing = autoClearing(loginUser, transitOrder);
        String msg = String.format("尊敬的车主用户您好，您的运单：%s（车辆：%s，司机：%s），货主方已确认收货，正在等待人工清算，清算时间由您的上游货主统一安排，对运费或清算时间有异议，请及时联系您的上游货主",
                transitOrder.getTransportNo(), transitOrder.getTransitTruckNo(), transitOrder.getTransitTruckUserName());
        if (clearing)
            msg = String.format("尊敬的车主用户您好，您的运单：%s（车辆：%s，司机：%s），货主方已确认收货，系统已自动清算，您的运费将在3个工作日内自动划到您的账户",
                    transitOrder.getTransportNo(), transitOrder.getTransitTruckNo(), transitOrder.getTransitTruckUserName());
        if (!autoConfirmReceipt) {
            messageRemote.sendOrderNotify(robAccount.getId(), msg, transitOwnerService.getTransitOrderDetailUrl(transitOrder.getId()));
        }
    }

    /**
     * 内部 自动清算
     */
    @Override
    public boolean autoClearing(Account loginUser, TransitOrder transitOrder) {
        if (transitOrder.getHandLiquidation()) return false;
        if (transitOrder.getPriceMode() == GoodsOrder.PriceMode.notPrice) return false;
        if (transitOrder.getAdditionalCost() != null && transitOrder.getAdditionalCost() != 0) return false;
        if (transitOrder.getDiffIndemnityCost() != null && transitOrder.getDiffIndemnityCost() != 0) return false;
        ClearingDetail clearingDetail = clearingService.getClearingDetailByTransitOrderId(transitOrder.getId());
        clearingDetail.setOptAccountId(loginUser.getId());
        clearingDetail.setOptAccountName(loginUser.getName());
        clearingDetail.setOptTime(new Date());
        clearingService.sureClearingDetail(loginUser, transitOrder, clearingDetail);
        return true;
    }

    /**
     * 运单中途换车/换人
     */
    @Override
    public void changeTruckOrUser(Account loginUser, TransitOrder localTransitOrder, TruckVehicle truckVehicle, TruckVehicle trailer) {
        TruckVehicle oldTruckVehicle = ParamUtil.isSuccess(vehicleRemote.getVehicleById(localTransitOrder.getTransitTruckId()));
        Account oldTruckUser = ParamUtil.isSuccess(userRemote.getAccountById(localTransitOrder.getTransitTruckUserId()));
        if (oldTruckVehicle.getId().equals(truckVehicle.getId()) && oldTruckUser.getId().equals(truckVehicle.getTruckUserId())) {
            throw new BusinessException("您未更换车辆或驾驶员，若无需更换，请通知原司机直接恢复运输！");
        }
        if (!oldTruckVehicle.getId().equals(truckVehicle.getId())) {
            //检查车辆信息
            ParamUtil.notEquals("更换车辆不在空闲中", truckVehicle.getTruckStatus(), TruckVehicle.TruckStatus.unused);
            ParamUtil.notEquals("更换车辆不属于您的组织", truckVehicle.getOrganizeId(), loginUser.getOrganizeId());
            TravelLicense travelLicense = ParamUtil.isSuccess(vehicleRemote.getTravelLicenseByVehicleId(truckVehicle.getId()));
            ParamUtil.isNull(travelLicense, "更换车辆未完成行驶证认证，请先完成认证");
            ParamUtil.notEquals("更换车辆行驶证认证未成功，请先完成认证", travelLicense.getAuthStatus(), AuthStatus.authSuccess);
            if (truckVehicle.getVehicleWeight() >= 4.5) {
                TransportLicense transportLicense = vehicleRemote.getTransportLicenseByVehicleId(truckVehicle.getId()).getData();
                ParamUtil.isNull(transportLicense, "更换车辆未完成道路运输证认证，请先完成认证");
                ParamUtil.notEquals("更换车辆未完成道路运输证认证，请先完成认证", transportLicense.getAuthStatus(), AuthStatus.authSuccess);
            }
            localTransitOrder.setTransitTruckId(truckVehicle.getId());
            localTransitOrder.setTransitTruckNo(truckVehicle.getTrackNo());
            localTransitOrder.setTransitTruckPlateColor(truckVehicle.getCardPlateName());

            localTransitOrder.setTransitTruckTypeId(truckVehicle.getTruckTypeId());
            localTransitOrder.setTransitTruckTypeName(truckVehicle.getTruckTypeName());
            localTransitOrder.setTransitCommTruckTypeId(truckVehicle.getCommTruckTypeId());
            localTransitOrder.setTransitCommTruckTypeName(truckVehicle.getCommTruckTypeName());

            localTransitOrder.setTransitTruckWeight(truckVehicle.getVehicleWeight());
            localTransitOrder.setTransitTruckLoadingWeight(truckVehicle.getLoadingWeight());
            localTransitOrder.setTransitTruckTypeImgPath(truckVehicle.getCommTruckTypeImg());
        }
        Account truckerUser = ParamUtil.isSuccess(userRemote.getAccountById(truckVehicle.getTruckUserId()));
        if (!oldTruckUser.getId().equals(truckerUser.getId())) {
            /// 验证司机信息
            ParamUtil.isNull(truckerUser, "未查询到更换司机");
//            ParamUtil.notEquals("更换司机已停用", truckerUser.getUserState(), Account.UserState.enable);
            ParamUtil.notEquals("更换司机不属于您的组织", truckerUser.getOrganizeId(), loginUser.getOrganizeId());
            DrivingLicense drivingLicense = ParamUtil.isSuccess(userRemote.getDrivingLicenseByUserId(truckerUser.getId()));
            ParamUtil.isNull(drivingLicense, "更换司机未完成驾驶证认证，请先联系司机完成认证");
            ParamUtil.notEquals("更换司机未完成驾驶证认证，请先联系司机完成认证", drivingLicense.getAuthStatus(), AuthStatus.authSuccess);
            if (truckVehicle.getVehicleWeight() >= 4.5) {
                QualificationCert qualificationCert = ParamUtil.isSuccess(userRemote.getQualificationCertByUserId(truckVehicle.getTruckUserId()));
                ParamUtil.isNull(qualificationCert, "车辆总质量大于4.5吨，请联系司机先完成从业资格证认证");
                ParamUtil.notEquals("车辆总质量大于4.5吨，请联系司机先完成从业资格证认证", qualificationCert.getAuthStatus(), AuthStatus.authSuccess);
            }
            localTransitOrder.setTransitTruckUserId(truckerUser.getId());
            localTransitOrder.setTransitTruckUserName(truckerUser.getName());
            localTransitOrder.setTransitTruckUserPhone(truckerUser.getPhone());
            localTransitOrder.setTransitTruckUserAvatar(truckerUser.getAvatar());
        }
        if (trailer != null) {
            /// 验证挂车信息
            ParamUtil.notEquals("更换挂车不在空闲中", trailer.getTruckStatus(), TruckVehicle.TruckStatus.unused);
            ParamUtil.notEquals("更换挂车不属于您的组织", trailer.getOrganizeId(), loginUser.getOrganizeId());
            TravelLicense travelLicense = ParamUtil.isSuccess(vehicleRemote.getTravelLicenseByVehicleId(trailer.getId()));
            ParamUtil.isNull(travelLicense, "更换挂车未完成行驶证认证，请先完成认证");
            ParamUtil.notEquals("更换挂车行驶证认证未成功，请先完成认证", travelLicense.getAuthStatus(), AuthStatus.authSuccess);
            if (trailer.getVehicleWeight() >= 4.5) {
                TransportLicense transportLicense = vehicleRemote.getTransportLicenseByVehicleId(trailer.getId()).getData();
                ParamUtil.isNull(transportLicense, "更换挂车未完成道路运输证认证，请先完成认证");
                ParamUtil.notEquals("更换挂车未完成道路运输证认证，请先完成认证", transportLicense.getAuthStatus(), AuthStatus.authSuccess);
            }
            localTransitOrder.setTransitTrailerNo(trailer.getTrackNo());
            localTransitOrder.setTransitTrailerWeight(trailer.getVehicleWeight());
            localTransitOrder.setTransitTrailerLoadingWeight(trailer.getLoadingWeight());
        }
        //结束旧的车辆运输记录并开始新的记录
        finishVehicleRecord(localTransitOrder, localTransitOrder.getTransitPauseCoordinate(), localTransitOrder.getTransitPauseAddress(), localTransitOrder.getTransitPauseAdCode());
        generateVehicleRecord(localTransitOrder, localTransitOrder.getTransitPauseCoordinate(), localTransitOrder.getTransitPauseAddress(), localTransitOrder.getTransitPauseAdCode());
        //更新运单
        localTransitOrder.setUpdateTime(new Date());
        localTransitOrder.setUpdateUserId(loginUser.getId());
        updateById(localTransitOrder);
        //保存操作日志
        orderAutLogService.saveTransitAutLog(localTransitOrder.getId(), loginUser, "中途更换车辆/司机",
                String.format("运单：%s，中途更换车辆，车牌号由 %s 更换为 %s，驾驶员由 %s 更换为 %s", localTransitOrder.getTransportNo(),
                        oldTruckVehicle.getTrackNo(), truckVehicle.getTrackNo(), oldTruckUser.getName(), truckerUser.getName()));
        //推送通知
        Account shipperAccount = ParamUtil.isSuccess(userRemote.getAccountById(localTransitOrder.getShipperAccountId()));
        String message = String.format("尊敬的货主用户您好，您的运单：%s，车主方已重新更换车辆/司机，请等待司机恢复运单", localTransitOrder.getTransportNo());
        messageRemote.sendOrderNotify(shipperAccount.getId(), message, transitOwnerService.getTransitOrderDetailUrl(localTransitOrder.getId()));
        //通知新的司机恢复运单
        if (!loginUser.getId().equals(truckerUser.getId()) && !oldTruckUser.getId().equals(truckerUser.getId())) {
            String message2 = String.format("尊敬的司机用户您好，您的车主管理员为您分配了一条中转运单：%s，请及时前往运单页面完成运单交接，并手动恢复运单", localTransitOrder.getTransportNo());
            messageRemote.sendOrderNotify(truckerUser.getId(), message2, transitOwnerService.getTransitOrderDetailUrl(localTransitOrder.getId()));
        }
    }

    /**
     * 申请暂停运单
     */
    @Override
    public void applyPausing(Account loginUser, TransitOrder localOrder) {
        localOrder.setOperateStatus(TransitOrder.OperateStatus.pausing);
        localOrder.setUpdateUserId(loginUser.getId());
        localOrder.setUpdateTime(new Date());
        updateById(localOrder);
        //暂停运单时，车辆将标记为损坏
        TruckVehicle truckVehicle = ParamUtil.isSuccess(vehicleRemote.getVehicleById(localOrder.getTransitTruckId()));
        vehicleRemote.updateVehicleStatus(localOrder.getTransitTruckId(), TruckVehicle.TruckStatus.repair);

        //判断是否同平台好运宝车辆，清除围栏信息
//        if (truckVehicle.getPlatId().equals(localOrder.getPlatId()) && truckVehicle.getTruckGpsType() == VehicleGps.TruckGpsType.hyb && truckVehicle.getGpsDeviceId() != null) {
//            EquipmentInfo equipmentInfo = ParamUtil.isSuccess(gpsRemote.getTrackDeviceInfo(truckVehicle.getPlatId(), truckVehicle.getGpsDeviceId()));
//            if (equipmentInfo != null && equipmentInfo.getStatus() != 3) ParamUtil.isSuccess(gpsRemote.deleteStoreDevicePolygon(truckVehicle.getPlatId(),localOrder.getTransportNo()));
//        }

        //推送通知
        if (!localOrder.getRobAccountId().equals(loginUser.getId())) {
            String message = String.format("尊敬的车主用户您好，您的运单：%s，司机方发起了运单暂停，请立即联系司机处理！", localOrder.getTransportNo());
            messageRemote.sendOrderNotify(localOrder.getRobAccountId(), message, transitOwnerService.getTransitOrderDetailUrl(localOrder.getId()));
        }
        String message = String.format("尊敬的货主用户您好，您的运单：%s 已被司机暂停，可能将导致运单延时，若对运输过程有异议，请及时联系车主处理！", localOrder.getTransportNo());
        messageRemote.sendOrderNotify(localOrder.getShipperAccountId(), message, transitOwnerService.getTransitOrderDetailUrl(localOrder.getId()));
    }

    /**
     * 申请恢复运单
     */
    @Override
    public void applyRecovery(Account loginUser, TransitOrder localTransitOrder) {
        localTransitOrder.setOperateStatus(TransitOrder.OperateStatus.none);
        localTransitOrder.setUpdateUserId(loginUser.getId());
        localTransitOrder.setUpdateTime(new Date());
        updateById(localTransitOrder);
        //恢复运单时，车辆将标记为使用中
        MemberType memberType = ParamUtil.isSuccess(userRemote.getMyMemberTypeByOrganizeId(loginUser.getOrganizeId()));
        TruckVehicle truckVehicle = ParamUtil.isSuccess(vehicleRemote.getVehicleById(localTransitOrder.getTransitTruckId()));
        vehicleRemote.updateVehicleStatus(localTransitOrder.getTransitTruckId(), TruckVehicle.TruckStatus.using);
        //重新生成围栏信息
        if (localTransitOrder.getTransitStatus() == TransitOrder.TransitStatus.waitingLoading
                || localTransitOrder.getTransitStatus() == TransitOrder.TransitStatus.waitingArrive) {
            List<TransitOrderNote> waitLoadingNoteList = getTransitOrderNoteList(localTransitOrder.getId(), TransitOrderNote.NoteStatus.waitLoading);
            List<TransitOrderNote> waitReceiptNoteList = getTransitOrderNoteList(localTransitOrder.getId(), TransitOrderNote.NoteStatus.waitReceipt);
            List<FenceInfoDTO> fenceInfoList = new ArrayList<>();
            for (TransitOrderNote transitOrderNote : waitLoadingNoteList) {
                fenceInfoList.add(FenceInfoDTO.genLoadingByTransitOrderNote(transitOrderNote, memberType.getElectronicFenceRange()));
            }
            for (TransitOrderNote transitOrderNote : waitReceiptNoteList) {
                fenceInfoList.add(FenceInfoDTO.genReceiptByTransitOrderNote(transitOrderNote, memberType.getElectronicFenceRange()));
            }
            //判断是否同平台好运宝车辆，配置装货围栏信息
//            if (truckVehicle.getPlatId().equals(localTransitOrder.getPlatId()) && truckVehicle.getTruckGpsType() == VehicleGps.TruckGpsType.hyb && truckVehicle.getGpsDeviceId() != null){
//                EquipmentInfo equipmentInfo = ParamUtil.isSuccess(gpsRemote.getTrackDeviceInfo(truckVehicle.getPlatId(), truckVehicle.getGpsDeviceId()));
//                if (equipmentInfo != null && equipmentInfo.getStatus() != 3) {
//                    String fenceInfoListJson = JsonUtil.objectToJson(fenceInfoList);
//                    ParamUtil.isSuccess(gpsRemote.storeDevicePolygon(truckVehicle.getPlatId(),localTransitOrder.getTransportNo(), truckVehicle.getTrackNo(),truckVehicle.getTruckUserName(),fenceInfoListJson));
//                }
//            }
        }
        //推送通知
        String message = String.format("尊敬的货主用户您好，您的运单：%s 已恢复运输，请及时关注运单状态，若对运输过程有异议，请及时联系车主处理！", localTransitOrder.getTransportNo());
        messageRemote.sendOrderNotify(localTransitOrder.getShipperAccountId(), message, transitOwnerService.getTransitOrderDetailUrl(localTransitOrder.getId()));
    }

    /**
     * 获取 待变更收货记录列表
     */
    @Override
    public List<ReceiptChangeRecord> getChangeNoteReceiptRecordList(String transitOrderId) {
        QueryWrapper<ReceiptChangeRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("transit_order_id", transitOrderId);
        queryWrapper.orderByDesc("create_time");
        return receiptChangeRecordMapper.selectList(queryWrapper);
    }

    /**
     * 批量获取 待变更收货记录列表
     */
    @Override
    public List<ReceiptChangeRecord> getMutiChangeNoteReceiptRecordList(List<String> transitOrderIds) {
        QueryWrapper<ReceiptChangeRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("transit_order_id", transitOrderIds);
        return receiptChangeRecordMapper.selectList(queryWrapper);
    }

    /**
     * 申请变更收货信息
     */
    @Override
    public void applyChangeNoteReceiptAddress(Account loginUser, ReceiptChangeRecord changeRecord) {
        if (loginUser.getUserType() != UserType.shipperUser) {
            throw new BusinessException("仅货主用户允许变更收货信息！");
        }
        TransitOrder localTransitOrder = transitOrderMapper.selectById(changeRecord.getTransitOrderId());
        if (!localTransitOrder.getShipperAccountId().equals(loginUser.getId())) {
            throw new BusinessException("仅运单货主允许变更收货信息！");
        }
        TransitOrderNote transitOrderNote = transitOrderNoteMapper.selectById(changeRecord.getTransitOrderNoteId());
        changeRecord.setOriginalConsigneeArea(transitOrderNote.getConsigneeArea());
        changeRecord.setOriginalConsigneeName(transitOrderNote.getConsigneeName());
        changeRecord.setOriginalConsigneePhone(transitOrderNote.getConsigneePhone());
        changeRecord.setOriginalConsigneeCoordinate(transitOrderNote.getConsigneeCoordinate());
        changeRecord.setOriginalConsigneeAddress(transitOrderNote.getConsigneeAddress());
        changeRecord.setOriginalConsigneeAdCode(transitOrderNote.getConsigneeAdCode());
        changeRecord.setFromAccountId(loginUser.getId());
        changeRecord.setFromName(loginUser.getName());
        //收货地址是否存在变动
        if (!changeRecord.getConsigneeCoordinate().equals(changeRecord.getOriginalConsigneeCoordinate())) {
            changeRecord.setChangeState(ReceiptChangeRecord.ChangeState.applying);
            receiptChangeRecordMapper.insert(changeRecord);
            //推送通知
            String message = String.format("尊敬的司机用户您好，您的运单：%s 货主发起了修改收货信息申请，请尽快处理！", localTransitOrder.getTransportNo());
            messageRemote.sendOrderNotify(localTransitOrder.getTransitTruckUserId(), message, transitOwnerService.getTransitOrderDetailUrl(localTransitOrder.getId()));
        } else {
            changeRecord.setChangeState(ReceiptChangeRecord.ChangeState.required);
            receiptChangeRecordMapper.insert(changeRecord);
            //推送通知
            String message = String.format("尊敬的司机用户您好，您的运单：%s 货主修改了部分收货联系信息，请尽快查看！", localTransitOrder.getTransportNo());
            messageRemote.sendOrderNotify(localTransitOrder.getTransitTruckUserId(), message, transitOwnerService.getTransitOrderDetailUrl(localTransitOrder.getId()));
        }
    }

    /**
     * 同意变更收货信息
     * 收货坐标存在变动，才需要司机去同意
     */
    @Override
    public void agreedChangeNoteReceiptAddress(Account loginUser, String changeRecordId) {
        ReceiptChangeRecord changeRecord = receiptChangeRecordMapper.selectById(changeRecordId);
        if (changeRecord.getChangeState() != ReceiptChangeRecord.ChangeState.applying) {
            throw new BusinessException("该条变更申请记录已完成！");
        }
        TransitOrderNote transitOrderNote = transitOrderNoteMapper.selectById(changeRecord.getTransitOrderNoteId());
        TransitOrder localTransitOrder = transitOrderMapper.selectById(changeRecord.getTransitOrderId());
        if (!localTransitOrder.getTransitTruckUserId().equals(loginUser.getId())) {
            throw new BusinessException("仅运单司机允许同意变更收货信息！");
        }
        transitOrderNote.setConsigneeArea(changeRecord.getConsigneeArea());
        transitOrderNote.setConsigneeName(changeRecord.getConsigneeName());
        transitOrderNote.setConsigneePhone(changeRecord.getConsigneePhone());
        transitOrderNote.setConsigneeCoordinate(changeRecord.getConsigneeCoordinate());
        transitOrderNote.setConsigneeAddress(changeRecord.getConsigneeAddress());
        transitOrderNote.setConsigneeAdCode(changeRecord.getConsigneeAdCode());
        transitOrderNoteMapper.updateById(transitOrderNote);
        changeRecord.setAgreeAccountId(loginUser.getId());
        changeRecord.setAgreeName(loginUser.getName());
        changeRecord.setDealTime(new Date());
        changeRecord.setChangeState(ReceiptChangeRecord.ChangeState.agreed);
        receiptChangeRecordMapper.updateById(changeRecord);
        //收货坐标存在变动，才需要司机去同意
        if (localTransitOrder.getTransitStatus() == TransitOrder.TransitStatus.waitingArrive) {
            //运输中：需要修改节点信息，如果节点ID是规划的终点，要同时标记强制结束信息
            if (localTransitOrder.getPlanningConsigneeNoteId().equals(transitOrderNote.getId())) {
                localTransitOrder.setForcedConsigneeAdCode(transitOrderNote.getConsigneeAdCode());
                localTransitOrder.setForcedConsigneeAddress(transitOrderNote.getConsigneeAddress());
                localTransitOrder.setForcedConsigneeCoordinate(transitOrderNote.getConsigneeCoordinate());
                transitOrderMapper.updateById(localTransitOrder);
            }
        }
        //推送通知
        String message = String.format("尊敬的货主用户您好，您的运单：%s 司机已同意了您的修改收货地址申请！", localTransitOrder.getTransportNo());
        messageRemote.sendOrderNotify(localTransitOrder.getShipperAccountId(), message, transitOwnerService.getTransitOrderDetailUrl(localTransitOrder.getId()));
    }

    /**
     * 拒绝变更收货信息
     */
    @Override
    public void refuseChangeNoteReceiptAddress(Account loginUser, String changeRecordId) {
        ReceiptChangeRecord changeRecord = receiptChangeRecordMapper.selectById(changeRecordId);
        if (changeRecord.getChangeState() != ReceiptChangeRecord.ChangeState.applying) {
            throw new BusinessException("该条变更申请记录已完成！");
        }
        TransitOrder localTransitOrder = transitOrderMapper.selectById(changeRecord.getTransitOrderId());
        if (!localTransitOrder.getTransitTruckUserId().equals(loginUser.getId())) {
            throw new BusinessException("仅运单司机允许拒绝变更收货信息！");
        }
        changeRecord.setChangeState(ReceiptChangeRecord.ChangeState.refused);
        changeRecord.setDealTime(new Date());
        receiptChangeRecordMapper.updateById(changeRecord);
        //推送通知
        String message = String.format("尊敬的货主用户您好，您的运单：%s 司机已拒绝您的修改收货地址申请，您可以与司机协商后再次发起！", localTransitOrder.getTransportNo());
        messageRemote.sendOrderNotify(localTransitOrder.getShipperAccountId(), message, transitOwnerService.getTransitOrderDetailUrl(localTransitOrder.getId()));
    }

    /**
     * 销单并退款
     *
     * @param cancellation 销单说明（原因）
     */
    @Override
    public void dealArbitrationRefund(Account loginUser, TransitOrder transitOrder, String cancellation) {
        //更新运单
        transitOrder.setTransitStatus(TransitOrder.TransitStatus.scraped);
        transitOrder.setUpdateTime(new Date());
        transitOrder.setUpdateUserId(loginUser.getId());
        QueryWrapper<TransitOrderNote> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("transit_order_id", transitOrder.getId());
        List<TransitOrderNote> detailList = transitOrderNoteMapper.selectList(queryWrapper);
        for (TransitOrderNote transitOrderNote : detailList) {
            transitOrderNote.setNoteStatus(TransitOrderNote.NoteStatus.scraped);
            transitOrderNote.setUpdateUserId(loginUser.getId());
            transitOrderNote.setUpdateTime(new Date());
            transitOrderNoteMapper.updateById(transitOrderNote);
        }
        saveOrUpdate(transitOrder);
        //退款操作

        //作废合同
        ParamUtil.isSuccess(dataRemote.cancellationContract(transitOrder.getId()));
        //更新运单挂车车辆状态
        if (!StringUtil.isEmpty(transitOrder.getTransitTrailerId())) {
            ParamUtil.isSuccess(vehicleRemote.updateVehicleStatus(transitOrder.getTransitTrailerId(), TruckVehicle.TruckStatus.unused));
        }
        //更新运单车辆状态
        ParamUtil.isSuccess(vehicleRemote.updateVehicleStatus(transitOrder.getTransitTruckId(), TruckVehicle.TruckStatus.unused));
        //保存操作日志
        String loggerText = String.format("运单销单成功，运单号：%s，销单原因：%s", transitOrder.getTransportNo(), cancellation);
        orderAutLogService.saveTransitAutLog(transitOrder.getId(), loginUser, "【销单成功】", loggerText);
    }

    /***
     * 获取所有运单车辆使用记录
     * */
    @Override
    public List<TransitOrderVehicleRecord> getTransitVehicleRecordList(String transitOrderId) {
        QueryWrapper<TransitOrderVehicleRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("transit_order_id", transitOrderId);
        return transitOrderVehicleRecordMapper.selectList(queryWrapper);
    }

    /**
     * 代开票状态
     */
    @Override
    public void updateTransitOrdersBillStatus(String[] transitOrderIds, Boolean status) {
        List<TransitOrder> list = transitOrderMapper.selectBatchIds(ArrayUtil.initList(transitOrderIds));
        for (TransitOrder transitOrder : list) transitOrder.setAlreadyBill(status);
        this.updateBatchById(list);
    }

    /**
     * 内部 生成新的车辆运输记录
     */
    private void generateVehicleRecord(TransitOrder localTransitOrder, String consignorCoordinate, String consignorAddress, String consignorAdCode) {
        //新建新的车辆运输 从暂停位置开始
        TransitOrderVehicleRecord vehicleRecord = new TransitOrderVehicleRecord();
        vehicleRecord.setRecordStatus(TransitOrderVehicleRecord.RecordStatus.current);
        vehicleRecord.setSplitStartTime(new Date());
        vehicleRecord.setTransitOrderId(localTransitOrder.getId());
        vehicleRecord.setTransportNo(localTransitOrder.getTransportNo());
        vehicleRecord.setTransitTruckId(localTransitOrder.getTransitTruckId());
        vehicleRecord.setTransitTruckNo(localTransitOrder.getTransitTruckNo());
        vehicleRecord.setTransitTruckPlateColor(localTransitOrder.getTransitTruckPlateColor());
        vehicleRecord.setTransitTruckUserId(localTransitOrder.getTransitTruckUserId());
        vehicleRecord.setTransitTruckUserName(localTransitOrder.getTransitTruckUserName());
        vehicleRecord.setTransitTruckUserPhone(localTransitOrder.getTransitTruckUserPhone());
        vehicleRecord.setTransitTrailerId(localTransitOrder.getTransitTrailerId());
        vehicleRecord.setTransitTrailerNo(localTransitOrder.getTransitTrailerNo());
        vehicleRecord.setSplitConsignorCoordinate(consignorCoordinate);
        vehicleRecord.setSplitConsignorAddress(consignorAddress);
        vehicleRecord.setSplitConsignorAdCode(consignorAdCode);
        transitOrderVehicleRecordMapper.insert(vehicleRecord);
    }

    /**
     * 内部 结束旧的车辆运输记录
     */
    private void finishVehicleRecord(TransitOrder localTransitOrder, String consigneeCoordinate, String consigneeAddress, String consigneeAdCode) {
        //結束原车辆运输记录 暂停位置结束
        QueryWrapper<TransitOrderVehicleRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("transit_order_id", localTransitOrder.getId());
        queryWrapper.eq("record_status", TransitOrderVehicleRecord.RecordStatus.current);
        TransitOrderVehicleRecord oldVehicleRecord = transitOrderVehicleRecordMapper.selectOne(queryWrapper);
        oldVehicleRecord.setSplitConsigneeCoordinate(consigneeCoordinate);
        oldVehicleRecord.setSplitConsigneeAddress(consigneeAddress);
        oldVehicleRecord.setSplitConsigneeAdCode(consigneeAdCode);
        oldVehicleRecord.setRecordStatus(TransitOrderVehicleRecord.RecordStatus.finish);
        oldVehicleRecord.setSplitEndTime(new Date());
        transitOrderVehicleRecordMapper.updateById(oldVehicleRecord);
    }

    /**
     * 内部 根据货主会员配置自动跳过发货
     */
    private boolean supportAutoDeliver(Account loginUser, TransitOrder localTransitOrder) {
        if (!localTransitOrder.getAutoDelivery()) return false;
        ///勾选自动发货，发货数据自动等于装货数据
        List<TransitOrderNote> noteList = transitOrderNoteMapper.selectList(new QueryWrapper<TransitOrderNote>()
                .eq("transit_order_id", localTransitOrder.getId()));
        for (TransitOrderNote transitOrderNote : noteList) {
            List<TransitOrderNoteDetail> detailList = transitOrderNoteDetailMapper.selectList(new QueryWrapper<TransitOrderNoteDetail>()
                    .eq("transit_order_note_id", transitOrderNote.getId()));
            detailList.forEach(transitNoteDetail -> transitNoteDetail.setDeliverMeasure(transitNoteDetail.getLoadingMeasure()));
            transitOrderNote.setTransitOrderNoteDetailList(detailList);
        }
        localTransitOrder.setTransitOrderNoteList(noteList);
        confirmDelivery(loginUser, localTransitOrder, true);
        return true;
    }

    /**
     * 内部 自动跳过回执
     */
    private boolean autoReceipt(Account loginUser, TransitOrder transitOrder) {
        //运单同时满足没有附加费、货主已付费用等于货主应付费用这两种情况才能自动签收
        boolean additionalCost = transitOrder.getAdditionalCost() == null || transitOrder.getAdditionalCost() == 0;
        //检查支付状态
        OrderPaymentCost paymentCost = orderPaymentCostService.generateReceiptOrderPayment(transitOrder);
        List<OrderPaymentCost.PayStatus> statusList = ArrayUtil.initList(OrderPaymentCost.PayStatus.none, OrderPaymentCost.PayStatus.complete);
        boolean paymentCompleted = statusList.contains(paymentCost.getPayStatus());
        if (transitOrder.getSkipConfirmReceipt() && additionalCost && paymentCompleted) {
            confirmReceipt(loginUser, transitOrder, true);
            return true;
        }
        return false;
    }

    /**
     * 定时任务强制确认回执
     */
    @Override
    public void autoConfirmReceipt() {
        //获取送达3天仍未收货的运单 当前时间-3天 < 送达时间
        String date = DateTimeUtil.dateToString(DateTimeUtil.plusDay(new Date(), -3));
        List<TransitOrder> list = list(new QueryWrapper<TransitOrder>().lt("receipt_time", date)
                .eq("transit_status", TransitOrder.TransitStatus.waitingReceipt.index)
                .eq("operate_status", TransitOrder.OperateStatus.none.index)
                .eq("clear_lock", 0));
        //自动确认回执
        for (TransitOrder transitOrder : list) {
            Account shipperAccount = ParamUtil.isSuccess(userRemote.getAccountById(transitOrder.getShipperAccountId()));
            confirmReceipt(shipperAccount, transitOrder, true);
        }
    }

    /**
     * 获取省运管需要重新生成的运单
     */
    @Override
    public List<TransitOrder> getErrorTmsTransitOrder(Integer transitTruckTowingType) {
        QueryWrapper<TransitOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("transit_status", TransitOrder.TransitStatus.complete);
        queryWrapper.and(qw -> qw.eq("tms_order_create_state", TransitOrder.TmsOrderCreateState.wait).or().eq("tms_order_create_state", TransitOrder.TmsOrderCreateState.error));
        if (transitTruckTowingType != null) {
            queryWrapper.eq("transit_truck_towing_type", transitTruckTowingType);
        }
        return transitOrderMapper.selectList(queryWrapper);
    }

    /**
     * 获取组织未完成的运单
     */
    @Override
    public List<TransitOrder> getRunTransitOrderByOrganizeId(String organizeId) {
        QueryWrapper<TransitOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.notIn("transit_status", TransitOrder.TransitStatus.complete, TransitOrder.TransitStatus.scraped);
        queryWrapper.and(cWrapper -> cWrapper.eq("shipper_organize_id", organizeId).or().eq("rob_organize_id", organizeId));
        return transitOrderMapper.selectList(queryWrapper);
    }

    /**
     * 获取账户未完成的运单
     */
    @Override
    public List<TransitOrder> getRunTransitOrderByAccountId(String accountId) {
        QueryWrapper<TransitOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.notIn("transit_status", TransitOrder.TransitStatus.complete, TransitOrder.TransitStatus.scraped);
        queryWrapper.and(cQueryWrapper -> cQueryWrapper.eq("shipper_account_id", accountId).or().eq("rob_account_id", accountId).or().eq("transit_truck_user_id", accountId));
        return transitOrderMapper.selectList(queryWrapper);
    }

    /**
     * 内批量查询订单
     */
    @Override
    public List<TransitOrder> getTransitOrderListByIds(String[] transitOrderIds) {
        return transitOrderMapper.selectBatchIds(Arrays.asList(transitOrderIds));
    }

    /**
     * 内批量查询订单2
     */
    @Override
    public List<TransitOrder> getTransitOrderListByNos(String[] transportNos) {
        QueryWrapper<TransitOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("transport_no", ArrayUtil.initList(transportNos));
        return transitOrderMapper.selectList(queryWrapper);
    }

    @Override
    public List<TransitOrderNote> getTransitOrderNoteListByTransitOrderIds(String[] transitOrderIds) {
        QueryWrapper<TransitOrderNote> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("transit_order_id", ArrayUtil.initList(transitOrderIds));
        return transitOrderNoteMapper.selectList(queryWrapper);
    }

    @Override
    public List<TransitOrderNoteDetail> getAllTransitDetailListByTransitOrderIds(String[] transitOrderIds) {
        QueryWrapper<TransitOrderNoteDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("transit_order_id", ArrayUtil.initList(transitOrderIds));
        return transitOrderNoteDetailMapper.selectList(queryWrapper);
    }

    @Override
    public TransitOrder getTransitOrderByNo(String transportNo) {
        return transitOrderMapper.selectOne(new QueryWrapper<TransitOrder>().eq("transport_no", transportNo));
    }

}
